/**
 * @(#)EmailServiceImpl.java 2010-2-22
 *   
 * Copyright  (c) 2009-2010 Wilmar IT Service,  Inc.   
 * All  rights  reserved.   
 * TODO
 */

package com.wilmar.process.core.services.impl;

import java.io.File;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import org.jbpm.pvm.internal.email.spi.MailSession;

import com.wilmar.process.core.ProcessSystemDeclareKeys;
import com.wilmar.process.core.services.spi.IEmailService;
import com.wilmar.process.core.services.spi.IUserService;
import com.wilmar.process.entity.Email;
import com.wilmar.process.entity.EmailSmtpAuth;
import com.wilmar.process.entity.Organization;
import com.wilmar.process.entity.ProcessParticipant;
import com.wilmar.process.entity.Role;
import com.wilmar.process.entity.User;
import com.wilmar.process.enumerate.EnumEmailSendingType;
import com.wilmar.process.system.ProcessSystem;

/**
 * 系统邮件接口实现类
 * 
 * @author Administrator Email:makubexnet@gmail.com
 * @version 1.0.0
 */
public class EmailServiceImpl implements IEmailService, MailSession {

	/**
	 * @serialField
	 */
	private static final long serialVersionUID = 1343488373276763676L;
	private IUserService userService;

	/**
	 * 核心的发送邮件代码,通常由本类自己调用
	 */
	private void send(Email email, EnumEmailSendingType sendingType) {
		if (sendingType == EnumEmailSendingType.THREAD)
			new Thread(new InnerMailSendingThread(email)).start();
		else if (sendingType == EnumEmailSendingType.ASSYNC)
			new InnerMailSendingThread(email).run();
	}

	/**
	 * 转换Email地址
	 */
	private Address[] transformEmailAddress(String emailAddresses)
			throws Exception {
		int pos = 0;
		int i = 0;
		Address[] addressArr;
		StringTokenizer st = null;
		String emailAddress;
		String address;
		String name;

		if (emailAddresses == null || emailAddresses.trim().length() == 0) {
			return null;
		}

		// 替换分割字符逗号、空格替换成分号
		emailAddresses = emailAddresses.replaceAll(
				ProcessSystemDeclareKeys.SPACE,
				ProcessSystemDeclareKeys.SEMICOLON);
		emailAddresses = emailAddresses.replaceAll(
				ProcessSystemDeclareKeys.COMMA,
				ProcessSystemDeclareKeys.SEMICOLON);

		st = new StringTokenizer(emailAddresses,
				ProcessSystemDeclareKeys.SEMICOLON);

		addressArr = new InternetAddress[st.countTokens()];

		while (st.hasMoreTokens()) {
			emailAddress = st.nextToken();
			pos = emailAddress.indexOf(ProcessSystemDeclareKeys.SLASH);
			if (pos == -1) {
				addressArr[i] = new InternetAddress(emailAddress);
			} else {
				address = emailAddress.substring(0, pos);
				name = emailAddress.substring(pos + 1);
				addressArr[i] = new InternetAddress(address, name);
			}
			i++;
		}
		return addressArr;
	}

	/**
	 * @return the userService
	 */
	public IUserService getUserService() {
		return userService;
	}

	/**
	 * @param userService
	 *            the userService to set
	 */
	public void setUserService(IUserService userService) {
		this.userService = userService;
	}

	/**
	 * @see com.wilmar.process.core.services.spi.IEmailService#getEmailAddressByUser(com.wilmar.process.entity.User)
	 */
	public String getEmailAddressByUser(User user) {
		if (user.getEmail() != null && user.getEmail().trim().length() > 0)
			return user.getEmail();
		else if (user.getBusinessEmail() != null
				&& user.getBusinessEmail().trim().length() > 0)
			return user.getBusinessEmail();
		return null;
	}

	/**
	 * @see com.wilmar.process.core.services.spi.IEmailService#
	 *      sendMailToProcessParticipant(com.wilmar.process.entity.Email,
	 *      com.wilmar.process.entity.ProcessParticipant)
	 */
	public void sendMailToProcessParticipant(Email email,
			ProcessParticipant processParticipant) {
		Set<User> userSet = new HashSet<User>();
		if (processParticipant.getUserSet() != null) {
			for (User u : processParticipant.getUserSet()) {
				userSet.add(this.userService.getDetailUserByUserno(u
						.getUserno(), u.getOuterSystem()));
			}
		}
		if (processParticipant.getRoleSet() != null) {
			for (Role role : processParticipant.getRoleSet()) {
				Set<User> ru = this.userService.getListUsersByRole(role, role
						.getOuterSystem());
				userSet.addAll(ru);
			}
		}
		if (processParticipant.getOrganizationSet() != null) {
			for (Organization org : processParticipant.getOrganizationSet()) {
				Set<User> ou = this.userService.getListUsersByOrganization(org,
						org.getOuterSystem());
				userSet.addAll(ou);
			}
		}
		User[] us = new User[userSet.size()];
		this.sendMailToUsers(email, userSet.toArray(us));
	}

	/**
	 * @see com.wilmar.process.core.services.spi.IEmailService#sendMailToUsers(com
	 *      .wilmar.process.entity.Email, com.wilmar.process.entity.User[])
	 */
	public void sendMailToUsers(Email email, User... users) {
		String address = "";
		for (User u : users) {
			if (u.getEmail() != null && u.getEmail().trim().length() > 0) {
				address += u.getEmail().trim();
				address += ProcessSystemDeclareKeys.COMMA;
			}
		}
		try {
			email.setToAddress((InternetAddress[]) this
					.transformEmailAddress(address));
		} catch (Exception e) {
			e.printStackTrace();
		}
		this.send(email,
				ProcessSystemDeclareKeys.PROCESS_SYSTEM_MAIL_SENDING_TYPE);
	}

	private class InnerMailSendingThread implements Runnable, Serializable {
		private Collection<Email> emails;

		/**
		 * @serialField
		 */
		private static final long serialVersionUID = -8441464138228832831L;

		public void run() {
			EmailSmtpAuth emailSmtpAuth = new EmailSmtpAuth(ProcessSystem
					.getEmailServer().getUser(), ProcessSystem.getEmailServer()
					.getPassword());
			Session mailSession = Session.getDefaultInstance(ProcessSystem
					.getEmailServer().toProperties(), emailSmtpAuth);
			for (Email email : emails) {
				MimeMessage message = new MimeMessage(mailSession);
				try {
					if (email.getFromAddress() != null) {
						message.setSender(email.getFromAddress());
						message.setFrom(email.getFromAddress());
					} else if (ProcessSystem.getEmailServer().getFrom() != null
							&& ProcessSystem.getEmailServer().getFrom().trim()
									.length() > 0) {
						message.setFrom(new InternetAddress(ProcessSystem
								.getEmailServer().getFrom().trim()));
						message.setSender(new InternetAddress(ProcessSystem
								.getEmailServer().getFrom().trim()));
					}
					if (email.getToAddress() != null)
						message.setRecipients(Message.RecipientType.TO, email
								.getToAddress());
					if (email.getCcAddress() != null)
						message.setRecipients(Message.RecipientType.CC, email
								.getCcAddress());
					if (email.getBccAddress() != null)
						message.setRecipients(Message.RecipientType.BCC, email
								.getBccAddress());
					if (email.getSubject() != null)
						message.setSubject(email.getSubject(), "GBK");
					// 构造Multipart
					Multipart mp = new MimeMultipart();
					// 向Multipart添加正文
					MimeBodyPart mbpContent = new MimeBodyPart();
					if (email.getEmailBody() != null) {
						mbpContent.setText(email.getEmailBody());
						// 向MimeMessage添加（Multipart代表正文）
						mp.addBodyPart(mbpContent);
						message.setContent(mp);
					}
					if (email.getAttachments() != null) {
						for (File attach : email.getAttachments()) {
							MimeBodyPart mbpFile = new MimeBodyPart();
							FileDataSource fds = new FileDataSource(attach
									.getName());
							mbpFile.setDataHandler(new DataHandler(fds));
							mbpFile.setFileName(fds.getName());
							// 向MimeMessage添加（Multipart代表附件）
							mp.addBodyPart(mbpFile);
						}
					}
					message.setSentDate(new Date());
					message.saveChanges();
					Transport.send(message, message.getAllRecipients());
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

		/**
		 * 默认构造函数
		 * 
		 * @param email
		 *            需要发送的邮件
		 */
		public InnerMailSendingThread(Email email) {
			super();
			this.emails = new HashSet<Email>();
			this.emails.add(email);
		}

		/**
		 * 根据一系列Message对象构造本类实例
		 * 
		 * @param messages
		 *            java.mail中的Message对象
		 */
		public InnerMailSendingThread(Collection<Message> messages) {
			this.emails = new HashSet<Email>();
			for (Message msg : messages) {
				this.emails.add(new Email(msg));
			}
		}

	}

	/**
	 * @see org.jbpm.pvm.internal.email.spi.MailSession#send(java.util.Collection)
	 */
	public void send(Collection<Message> arg0) {
		if (ProcessSystemDeclareKeys.PROCESS_SYSTEM_MAIL_SENDING_TYPE == EnumEmailSendingType.THREAD)
			new Thread(new InnerMailSendingThread(arg0)).start();
		else if (ProcessSystemDeclareKeys.PROCESS_SYSTEM_MAIL_SENDING_TYPE == EnumEmailSendingType.ASSYNC)
			new InnerMailSendingThread(arg0).run();
	}
}
